/**
 * 作者：
 * 创建时间：2012-6-28 下午5:30:14
 */
package dragon.model.bizObject;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dragon.core.cache.CacheManager;
import dragon.core.cache.Caches;
import dragon.core.db.DML;
import dragon.core.exception.ExceptionHandler;
import dragon.core.io.FileHandler;
import dragon.core.util.FilePath;
import dragon.core.util.StringUtils;
import dragon.model.base.ModelSort;
import dragon.model.table.Table;

/**
 * 业务模型容器
 */
public class BizObjectContainer {
	/**
	 * 业务模型容器对象，用于存储系统中定义的所有业务模型对象<br>
	 * k:业务模型唯一标识符(code),v:BizObject
	 */
	private static Map<String, BizObject> container = new HashMap<String, BizObject>();

	/**
	 * 加载全部业务模型
	 * 
	 * @throws ExceptionHandler
	 */
	public static void loadAll() throws ExceptionHandler {
		container.clear();// 先清空

		List<File> files = FileHandler.getFiles(FilePath.MODEL_BIZOBJECT, 0, true);
		for (File file : files) {
			if (file.isDirectory()) {
				continue;
			}
			load(file.getAbsolutePath());
		}
	}

	/**
	 * 加载指定业务模型
	 * 
	 * @param filePath
	 *            业务模型xml配置文件路径
	 * @return
	 * @throws ExceptionHandler
	 */
	public static BizObject load(String filePath) throws ExceptionHandler {
		BizObject bizObject = BizObjectParser.parse(filePath);
		if (bizObject != null) {
			container.put(bizObject.getCode(), bizObject);
		}
		return bizObject;
	}

	/**
	 * 从集合中查找业务模型对象
	 * 
	 * @param code
	 *            业务模型唯一标识符(code)
	 * @return
	 */
	public static BizObject get(String code) throws ExceptionHandler {
		if (code == null || StringUtils.isEmpty(code)) {
			return null;
		}
		return container.get(code);
	}

	/**
	 * 返回所有业务模型定义
	 * 
	 * @return
	 */
	public static BizObject[] getAll() {
		BizObject[] bizObjects = new BizObject[container.size()];
		@SuppressWarnings({ "unchecked", "rawtypes" })
		List<Table> list = new ArrayList(container.values());
		Collections.sort(list, new ModelSort());
		list.toArray(bizObjects);
		list = null;
		return bizObjects;
	}

	/**
	 * 返回业务模型个数
	 * 
	 * @return
	 */
	public static int size() {
		return container.size();
	}

	/**
	 * 业务模型加载完成后的后续处理
	 * 
	 * @throws ExceptionHandler
	 */
	public static void afterLoad() throws ExceptionHandler {
		for (BizObject bizObject : getAll()) {
			// 处理依赖(主从表)关系
			handleDepend(bizObject);
		}

		// 缓存业务模型业务操作权限限定集
		cacheModelProcessPermissions();
	}

	/**
	 * 处理依赖(主从表)关系
	 * 
	 * @param bizObject
	 *            业务对象
	 * @throws ExceptionHandler
	 */
	private static void handleDepend(BizObject bizObject) throws ExceptionHandler {
		// depend和dependParam属性检查，此两个属性要么同时配置，要么都不配置，只配置一个是错误的
		if (((bizObject.getDepend() == null || StringUtils.isEmpty(bizObject.getDepend())) && (bizObject.getDependParam() != null && !StringUtils.isEmpty(bizObject.getDependParam())))
				|| ((bizObject.getDepend() != null && !StringUtils.isEmpty(bizObject.getDepend())) && (bizObject.getDependParam() == null || StringUtils.isEmpty(bizObject.getDependParam())))) {
			throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  depend，dependParam 需要同时配置", bizObject.getName(), bizObject.getCode()));
		}

		// 存在主从关系
		if (bizObject.getDepend() != null && !StringUtils.isEmpty(bizObject.getDepend())) {

			/**
			 * 解析依赖的业务模型对象
			 */
			// if (bizObject.getCode().equals(bizObject.getDepend())) {
			// throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  depend 不能引用其自身！", bizObject.getName(), bizObject.getCode()));
			// }

			BizObject depend = BizObjectContainer.get(bizObject.getDepend());
			if (depend == null) {
				throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  depend 指示的业务模型对象不存在！", bizObject.getName(), bizObject.getCode()));
			}

			// 设置依赖业务模型对象
			bizObject.setDependon(depend);
			if (bizObject.getDependShow() == 1) {
				if (depend.getDependby() == null) {
					List<BizObject> dependby = new ArrayList<BizObject>();
					dependby.add(bizObject);
					depend.setDependby(dependby);
					dependby = null;
				} else {
					depend.getDependby().add(bizObject);
				}
			}

			/**
			 * 解析依赖参数，k=v，k是从表业务模型中的查询字段code，v是主表业务模型中的业务字段code
			 */
			String[] kv = bizObject.getDependParam().split("=");
			if (kv.length != 2) {
				throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  dependParam 格式错误，正确格式为 k=v ！", bizObject.getName(), bizObject.getCode()));
			}

			// 解析从表业务模型中的查询字段
			if (bizObject.getQueryFieldByCode(kv[0]) == null) {
				throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  dependParam 中指定的从表业务模型中的查询字段 %s 不存在 ！", bizObject.getName(), bizObject.getCode(), kv[0]));
			}

			// 解析主表业务模型中的业务字段
			if (depend.getBizFieldByCode(kv[1]) == null) {
				throw new ExceptionHandler(String.format("业务模型 %s[%s] 属性  dependParam 中指定的主表业务模型中的业务字段 %s 不存在 ！", bizObject.getName(), bizObject.getCode(), kv[1]));
			}

		}

	}

	/**
	 * 缓存业务操作权限限定集
	 * 
	 * @throws ExceptionHandler
	 */
	@SuppressWarnings("unchecked")
	private static void cacheModelProcessPermissions() throws ExceptionHandler {

		// Step1 初始化缓存
		CacheManager.getCache(Caches.model_process_permissions.name(), true).clear();
		HashMap<String, List<Integer>> map = null;
		for (BizObject bizObject : getAll()) {
			if (bizObject.getProcesses() != null) {
				for (BizProcess process : bizObject.getProcesses()) {
					map = new HashMap<String, List<Integer>>(3);
					map.put("R", new ArrayList<Integer>(5));
					map.put("O", new ArrayList<Integer>(5));
					map.put("U", new ArrayList<Integer>(5));
					CacheManager.put(Caches.model_process_permissions.name(), (bizObject.getCode() + "_" + process.getCode()).toUpperCase(), map);
				}
			}
		}

		// Step2 读取数据库配置信息
		String sql = "select bizcode,process,kind,tid from sys.model_process_permissions";
		List<Map<String, Object>> list = DML.query(sql);

		// Step3 将配置信息压入缓存
		Object obj = null;
		String kind = null;
		String tid = null;
		for (Map<String, Object> item : list) {
			obj = CacheManager.get(Caches.model_process_permissions.name(), (item.get("BIZCODE").toString() + "_" + item.get("PROCESS")).toUpperCase());
			if (obj == null) {
				continue;
			}
			map = (HashMap<String, List<Integer>>) obj;
			kind = item.get("KIND").toString();
			tid = item.get("TID").toString();

			if ("R".equals(kind)) {
				map.get("R").add(Integer.parseInt(tid));
			} else if ("O".equals(kind)) {
				map.get("O").add(Integer.parseInt(tid));
			} else if ("U".equals(kind)) {
				map.get("U").add(Integer.parseInt(tid));
			}
		}

		obj = null;
		map = null;
		list = null;

	}
}
